#pragma once

#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>

#include "../Comm/util.hpp"
#include "../Comm/Log.hpp"

namespace ns_compiler
{
    class Compiler
    {
    public:
        Compiler() {}
        ~Compiler() {}

    public:
        // 传入文件名 例如：1234
        // 1234 --> ./temp/1234.cpp     源文件
        // 1234 --> ./temp/1234.exe     形成的可执行程序
        // 1234 --> ./temp/1234.stderr  错误输出
        static bool Compile(const std::string &file_name)
        {
            pid_t pid = fork();
            if (pid < 0){
                LOG(ERROR,"创建子进程失败");
                return false;
            }
            else if (pid == 0){ // child
                
                // 将g++编译错误的内容重定向到指定的文件中
                umask(0);
                int _stderr = ::open(ns_util::PathUtil::CompileErr(file_name).c_str(), O_CREAT | O_WRONLY, 0664);
                if (_stderr < 0){
                    LOG(ERROR,"open %s failed",ns_util::PathUtil::CompileErr(file_name).c_str());
                    exit(1);
                }
                // 错误信息重定向到_stderr
                ::dup2(_stderr, 2);

                // 程序替换，执行g++编译程序
                ::execlp("g++","g++", "-o", ns_util::PathUtil::Exe(file_name).c_str(),
                        ns_util::PathUtil::Src(file_name).c_str(),"-std=c++11","-D","COMPILER_ONLINE",nullptr);

                LOG(WARNING,"程序替换出错,可能是g++ 参数错误");
                exit(2);
            }
            else{  // father
                ::waitpid(pid, nullptr, 0);
                // 判断exe文件是否存在，如果存在，则说明编译成功，否则失败
                if (ns_util::FileUtil::FileIsExist(ns_util::PathUtil::Exe(file_name).c_str())){
                    LOG(INFO,"%s 编译成功",ns_util::PathUtil::CompileErr(file_name).c_str());
                    return true;
                }
            }
            LOG(INFO,"%s 编译出错",ns_util::PathUtil::CompileErr(file_name).c_str());
            return false;
        }
    };
}